package cn.jtfadmin.base.dict.service;

import cn.jtfadmin.base.dict.dto.DictItemModelDTO;
import cn.jtfadmin.base.lang.common.domain.dto.SpecConditionDTO;
import cn.jtfadmin.base.lang.common.domain.dto.SpecPDTO;
import cn.jtfadmin.base.lang.common.domain.entity.IdEntity;
import cn.jtfadmin.base.lang.common.domain.entity.NamedEntity;
import cn.jtfadmin.base.lang.common.service.BaseService;
import cn.jtfadmin.base.lang.common.utils.JsonUtils;
import cn.jtfadmin.base.lang.common.utils.ReflectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 字典服务类
 * @author jtf
 * @since 0.0.1
 */
public interface DictEntityService<T extends IdEntity>  {
    /**
     * 按照id获取字典信息
     * @param columns 显示列
     * @param ids ids
     * @return
     */
    default List<DictItemModelDTO> findDictModelListByIds(@Nullable String columns, @NotBlank String ids ){
        return findDictModelListByIds(columns, ids, null);
    }

    /**
     * 按照查询条件查询字典信息
     * @param columns 显示列
     * @param specPDTO 条件
     * @return
     */
    default List<DictItemModelDTO> findDictModelListBySpec(@Nullable String columns,  SpecPDTO<T> specPDTO){
        return findDictModelListBySpec(columns, specPDTO, null);
    }

    /**
     * 查询所有的字典信心
     * @param columns 列
     * @return
     */
    default List<DictItemModelDTO> findDictModelList(@Nullable String columns){
        return findDictModelList(columns, null);
    }

    /**
     * 按照id获取字典信息
     * @param columns 显示列
     * @param ids ids
     * @param keyField 字典值的列
     * @return
     */
    default List<DictItemModelDTO> findDictModelListByIds(@Nullable String columns, @NotBlank String ids,  @Nullable String keyField  ){
        SpecPDTO<T> specPDTO = new SpecPDTO<>();
        SpecConditionDTO dto = new SpecConditionDTO();
        dto.setColumn("id");
        dto.setType("in");
        dto.setValue(ids);
        specPDTO.setSpecJson(JsonUtils.toJsonStr(Arrays.asList(dto)));

        return findDictModelListBySpec(columns, specPDTO, keyField);
    }

    /**
     * 按照查询条件查询字典信息
     * @param columns 显示列
     * @param specPDTO 条件
     * @param keyField 字典值的列
     * @return
     */
    default List<DictItemModelDTO> findDictModelListBySpec(@Nullable String columns,  @Nullable SpecPDTO<T> specPDTO,
                                                           @Nullable String keyField ){
        if(!StringUtils.hasText(columns)){
            if(NamedEntity.class.isAssignableFrom(getEntityClass())
            ||  (BeanUtils.getPropertyDescriptor(getEntityClass()," name")!=null
                    && BeanUtils.getPropertyDescriptor(getEntityClass()," name").getReadMethod()!=null))
            {
                columns = "name";
            } else{
                columns = "id";
            }
        }

        return entityToItemModel(findAll(specPDTO),keyField, StringUtils.commaDelimitedListToStringArray(columns));
    }

    /**
     * 查询所有的字典信心
     * @param columns 列
     * @param keyField 字典值的列
     * @return
     */
    default List<DictItemModelDTO> findDictModelList(@Nullable String columns, @Nullable String keyField){
        return findDictModelListBySpec(columns, null, keyField);
    }

    /**
     * 将实体类转换为字典模型
     * @param objects 对象
     * @param keyField 字典值的列
     * @param showFields 展示的列
     * @return
     */
    default List<DictItemModelDTO> entityToItemModel(@NotNull List<T> objects, @Nullable String keyField, String... showFields){
       return entityToItemModel(objects, keyField, false, showFields);
    }



    /**
     * 将实体类转换为字典模型
     * @param objects 对象
     * @param keyField 字典值的列
     * @param fillSource 是否填充源数据
     * @param showFields 展示的列
     * @return
     */
    default List<DictItemModelDTO> entityToItemModel(@NotNull List<T> objects, @Nullable String keyField,boolean fillSource, String... showFields){
        return
                new ArrayList<>(objects.stream().map(t-> {
                    String key = null;
                    if(!StringUtils.hasText(keyField)){
                        key = t.getId();
                    }else {
                        key = ReflectionUtils.getFieldValueStr(t, keyField);
                    }
                    List<String> showFiledsTextList = new ArrayList<>(showFields.length);
                    for (String showField : showFields) {
                        String property = ReflectionUtils.getFieldValueStr(t, showField);
                        showFiledsTextList.add(property);
                    }
                    if (showFiledsTextList.isEmpty()) {
                        return new DictItemModelDTO(key, "--", fillSource?t:null);
                    } else {
                        return new DictItemModelDTO(key, StringUtils.collectionToDelimitedString(showFiledsTextList, "--"),fillSource?t:null);
                    }
                }).collect(Collectors.toSet()));
    }

    List<T> findAll(@Nullable SpecPDTO<T> specPDTO);

    Class<?> getEntityClass();
}
